﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using MARZ_Script.analysis;
using MARZ_Script.lexer;
using MARZ_Script.node;
using MARZ_Script.parser;


/**
 *(DONE? QA) Create proper type checking (eg. allow float = int + float and disallow string * string. And so on). At the moment it just checks that its the same types on both sides of an expression
 * TODO Clean code in functionscall region
 *  
 * TODO Add special functions
 *  -add vector operations, as functions? Operators?
 *  
 * TODO implement reachability and termination analysis - Fischer 9.1.1 page 345
 *  -in extension add checking for return statment - return statment page 361 in fischer 9.1.5
 * */

namespace SableCC15
{
    /// <summary>
    /// Semantic exception used to encapsulate errors thrown during semantic analysis
    /// </summary>
    public class SemanticException : ApplicationException
    {
        public SemanticException(String message)
            : base(message)
        {
        }
    }

    enum scopes { Closed = -1, Templates, Start, Update, Draw, Functions };

    class SemanticAnalyser : DepthFirstAdapter
    {
        private List<Exception> _exceptionList = new List<Exception>();

        /// <summary>
        /// Contains all the exceptions cast during the semantic analysis
        /// </summary>
        public List<Exception> ExceptionList { get { return _exceptionList; } }

        public SymbolTable SymbolTable = SymbolTable.GetInstance();

        /// <summary>
        /// Current template or function being worked on
        /// </summary>
        private string scopeName = ""; //for templates and functions
        private int scopeLevel = 0;
        private bool isDraw = false;
        private List<VariableEntry> drawFunctions = new List<VariableEntry>();
        private List<string> keyEventListeneres = new List<string>();
        static public List<VariableEntry> DrawFunctions;
        public SemanticAnalyser()
        {
            DrawFunctions = drawFunctions;
            VariableEntry drawImage = new VariableEntry() { Id = "DrawImage", Scope = scopes.Draw.ToString(), ScopeLevel = 0, DataType = "function", IsDrawFunction = true };
            drawImage.ParamEnqueue(new VariableEntry() { DataType = "string" });
            drawImage.ParamEnqueue(new VariableEntry() { DataType = "coord" });
            drawFunctions.Add(drawImage);

            VariableEntry drawRectangle = new VariableEntry() { Id = "DrawRectangle", Scope = scopes.Draw.ToString(), ScopeLevel = 0, DataType = "function", IsDrawFunction = true };
            drawRectangle.ParamEnqueue(new VariableEntry() { DataType = "coord" });
            drawRectangle.ParamEnqueue(new VariableEntry() { DataType = "coord" });
            drawRectangle.ParamEnqueue(new VariableEntry() { DataType = "string" });
            drawFunctions.Add(drawRectangle);

            VariableEntry drawCircle = new VariableEntry() { Id = "DrawCircle", Scope = scopes.Draw.ToString(), ScopeLevel = 0, DataType = "function", IsDrawFunction = true };
            drawCircle.ParamEnqueue(new VariableEntry() { DataType = "coord" });
            drawCircle.ParamEnqueue(new VariableEntry() { DataType = "float" });
            drawCircle.ParamEnqueue(new VariableEntry() { DataType = "string" });
            drawFunctions.Add(drawCircle);

            VariableEntry printText = new VariableEntry() { Id = "PrintText", Scope = scopes.Draw.ToString(), ScopeLevel = 0, DataType = "function", IsDrawFunction = true };
            printText.ParamEnqueue(new VariableEntry() { DataType = "coord" });
            printText.ParamEnqueue(new VariableEntry() { DataType = "string" });
            printText.ParamEnqueue(new VariableEntry() { DataType = "int" });
            drawFunctions.Add(printText);

            VariableEntry isColliding = new VariableEntry() { Id = "IsColliding", Scope = scopes.Functions.ToString(), ScopeLevel = 0, DataType = "function", IsDrawFunction = true };
            isColliding.ParamEnqueue(new VariableEntry() { DataType = "coord", Scope = isColliding.Id });
            isColliding.ParamEnqueue(new VariableEntry() { DataType = "coord", Scope = isColliding.Id });
            isColliding.ParamEnqueue(new VariableEntry() { DataType = "coord", Scope = isColliding.Id });
            isColliding.ParamEnqueue(new VariableEntry() { DataType = "coord", Scope = isColliding.Id });
            isColliding.DataType = "bool"; //Set return type
            SymbolTable.Add(isColliding);
            drawFunctions.Add(isColliding);

            VariableEntry listAdd = new VariableEntry() { Id = "ListAdd", Scope = scopes.Functions.ToString(), ScopeLevel = 0, DataType = "function", IsListFunction = true };
            listAdd.ParamEnqueue(new VariableEntry() { DataType = "List", Scope = listAdd.Id });
            listAdd.ParamEnqueue(new VariableEntry() { DataType = "", Scope = listAdd.Id });
            SymbolTable.Add(listAdd);

            VariableEntry listRemove = new VariableEntry() { Id = "ListRemove", Scope = scopes.Functions.ToString(), ScopeLevel = 0, DataType = "function", IsListFunction = true };
            listRemove.ParamEnqueue(new VariableEntry() { DataType = "List", Scope = listRemove.Id });
            listRemove.ParamEnqueue(new VariableEntry() { DataType = "", Scope = listRemove.Id });
            //return type needs to be set after we've determined secondparam data type - which is done on the MultipleExpressionSequence node

            SymbolTable.Add(listRemove);

            VariableEntry listGet = new VariableEntry() { Id = "ListGet", Scope = scopes.Functions.ToString(), ScopeLevel = 0, DataType = "function", IsListFunction = true };
            listGet.ParamEnqueue(new VariableEntry() { DataType = "List", Scope = listGet.Id });
            listGet.ParamEnqueue(new VariableEntry() { DataType = "", Scope = listGet.Id });
            SymbolTable.Add(listGet);

            VariableEntry listCount = new VariableEntry() { Id = "ListCount", Scope = scopes.Functions.ToString(), ScopeLevel = 0, DataType = "function", IsListFunction = true };
            listCount.ParamEnqueue(new VariableEntry() { DataType = "List", Scope = listCount.Id });
            listCount.DataType = "int"; //Set return type
            SymbolTable.Add(listCount);
        }

        #region progTraversel
        /// <summary>
        /// To control which order we run through the sub-trees of the prog node. To make sure template and functions are run first to define their id.
        /// Need to make sure the ids are defined first otherwise the order of writing the functions matter. Ie. cant use a function defined below the function your currently in.
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAProg(AProg node)
        {
            IdCollector funcs = new IdCollector(drawFunctions, ref _exceptionList);
            //Apply here will traverse the entire sub-tree. But we only need the id from the headers, any way to avoid this?
            node.GetTemplates().Apply(funcs);
            node.GetFunctions().Apply(funcs);

            scopeName = scopes.Closed.ToString();

            //normally the "case" function calls the "in" "out" functions, we still want it to do that
            base.CaseAProg(node);
        }

        /// <summary>
        /// Applies the semantic analyser on the subtree of each template, and creates a scope for each template
        /// </summary>
        /// <param name="node"></param>
        public override void CaseATempl(ATempl node)
        {
            scopeName = node.GetId().Text; //Sets the current scope

            node.GetTemplateBody().Apply(this);
            scopeName = scopes.Closed.ToString(); //Sets the current scope
        }

        /// <summary>
        /// Applies the semantic analyser to the subtree of the start function
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAStart(AStart node)
        {
            scopeName = scopes.Start.ToString(); //Sets the current scope
            node.GetBodyList().Apply(this); //applies the analyser to the subtree
            scopeName = scopes.Closed.ToString(); //closes the scope so that in case anything should run without proberbly setting the scope nothing is added to this scope accidently
        }

        /// <summary>
        /// Applies the semantic analyser to the subtree of the update function
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAUpdate(AUpdate node)
        {
            scopeName = scopes.Start.ToString(); //Sets the current scope
            node.GetBodyList().Apply(this); //applies the analyser to the subtree
            scopeName = scopes.Closed.ToString(); //closes the scope so that in case anything should run without proberbly setting the scope nothing is added to this scope accidently
        }

        /// <summary>
        /// Applies the semantic analyser to the subtree of the draw function
        /// </summary>
        /// <param name="node"></param>
        public override void CaseADraw(ADraw node)
        {
            isDraw = true;
            scopeName = scopes.Start.ToString(); //Sets the current scope
            //_symbolTable.Add((int)scopeName, new Hashtable()); //adds the draw scope
            node.GetBodyList().Apply(this);
            scopeName = scopes.Closed.ToString(); //closes the scope so that in case anything should run without proberbly setting the scope nothing is added to this scope accidently
            isDraw = false;
        }

        /// <summary>
        /// Applies the semantic analyser to each declared functions subtree, and creates a scope for each function
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAFunc(AFunc node)
        {
            scopeName = node.GetId().Text; //Sets the current scope

            node.GetBodyList().Apply(this);
            VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopes.Functions.ToString());
            if (!ve.NumericValue && ve.DataType != "void")
                _exceptionList.Add(new SemanticException(string.Format("Function {0} isnt guranteed a return value, Line:{1}", node.GetId().Text, node.GetId().Line)));
            scopeName = scopes.Closed.ToString(); //Sets the current scope
        }
        #endregion

        #region varDeclAndInit
        /// <summary>
        /// Typechecks a initializing declaration and adds the id and type to the current scopes symbol table
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAInitDeclVarDecl(AInitDeclVarDecl node)
        {
            node.GetExpression().Apply(this); //evaluates the expression on the right hand side of the declaration to a type
            string expressionType = node.GetExpression().NodeType;

            ADecl dec = (ADecl)node.GetDecl();
            string declType = dec.GetType().ToString().ToLower().Trim();

            string error = String.Format("Type {0} and type {1} dont match. Line:{2}, pos:{3}", dec.GetType(), node.NodeType, node.GetBe().Line, node.GetBe().Pos);
            if (!(dec.GetType() is AIdType))
            {

                if (dec.GetTList() == null)
                {
                    switch (declType) //compares the declared type and the type being assigned
                    {
                        case "float": //float is a special case, because its the only case where you can assign more than one type
                            if (expressionType.Contains("float") || expressionType.Contains("int"))
                                AddId(dec);
                            else
                                _exceptionList.Add(new SemanticException(error));
                            break;
                        case "entity": //entity is a special case becuase you have to access the member type
                            string ad = node.GetExpression().ToString();
                            if (expressionType == "templates")
                            {
                                //check if valid template exists then add declaring id to scope and have template info added aswell
                                if (!SymbolTable.VariableExists(dec.GetId().Text, scopeName, scopeLevel))
                                    SymbolTable.Add(new VariableEntry() { Id = dec.GetId().Text.Trim(), DataType = node.GetExpression().ToString().Trim(), Scope = scopeName, ScopeLevel = scopeLevel });
                            }
                            else
                                _exceptionList.Add(new SemanticException(String.Format("For entity you need a valid Template, no template by {0} where found. Line:{1}, pos{2}",
                                    ad, node.GetBe().Line, node.GetBe().Pos)));
                            break;
                        default: //default case, compares declared tyåe to expression type if they match adds the id with type to the current scopes symbol table                        
                            if (expressionType.Contains(declType))
                                AddId(dec);
                            else
                                _exceptionList.Add(new SemanticException(error));
                            break;
                    }
                }
                else
                {
                    _exceptionList.Add(new SemanticException(string.Format("Cant instanciate a list variable, Line:{0} pos:{1}", node.GetBe().Line, node.GetBe().Pos)));
                }
            }
            else _exceptionList.Add(new SemanticException(string.Format("Invalid type {2} did you mean to use an entity, Line:{0} pos:{1}", node.GetBe().Line, node.GetBe().Pos, declType)));


        }

        /// <summary>
        /// Adds a declarion to the current scopes symbol table
        /// </summary>
        /// <param name="node"></param>
        public override void CaseADeclVarDecl(ADeclVarDecl node)
        {
            ADecl dec = (ADecl)node.GetDecl();
            if (dec.GetTList() != null)
            {
                if (SymbolTable.VariableExists(dec.GetId().Text, scopes.Functions.ToString(), 0))
                    _exceptionList.Add(new SemanticException(String.Format("Id: {0} already exsists as a function or template. Line:{1}, pos:{2}", dec.GetId(), dec.GetId().Line, dec.GetId().Pos)));
                else if (!SymbolTable.VariableExists(dec.GetId().Text, scopeName.ToString(), scopeLevel))
                    SymbolTable.Add(new VariableEntry() { Id = dec.GetId().Text, Scope = scopeName.ToString(), ScopeLevel = scopeLevel, DataType = "List" + dec.GetType().ToString().Trim() });
                else _exceptionList.Add(new SemanticException(String.Format("Id: {0} already exsists. Line:{1}, pos:{2}", dec.GetId(), dec.GetId().Line, dec.GetId().Pos)));
            }
            else
            {
                if (dec.GetType() is AIdType)
                    _exceptionList.Add(new SemanticException(string.Format("Invalid type {2} did you mean to use an entity? Try \"Let entity {3} Be {2}\", Line:{0} pos:{1}",
                        dec.GetLet().Line, dec.GetLet().Pos, dec.GetType().ToString(), dec.GetId().ToString())));
                else if (dec.GetType() is AEntityType)
                    _exceptionList.Add(new SemanticException(string.Format("An entity type needs to be instanciated with a valid template type, Line:{0} pos:{1}", dec.GetLet().Line, dec.GetLet().Pos, dec.GetType().ToString())));
                else
                    AddId(dec);
            }
        }

        /// <summary>
        /// Adds the id and type from node to the current scopes symbol table
        /// When running this code typechecking must have occured
        /// </summary>
        /// <param name="node"></param>
        public void AddId(ADecl node)
        {
            if (SymbolTable.VariableExists(node.GetId().Text, scopes.Functions.ToString(), 0))
                _exceptionList.Add(new SemanticException(String.Format("Id: {0} already exsists as a function or template. Line:{1}, pos:{2}", node.GetId(), node.GetId().Line, node.GetId().Pos)));
            else if (!SymbolTable.VariableExists(node.GetId().Text, scopeName.ToString(), scopeLevel))
                SymbolTable.Add(new VariableEntry() { Id = node.GetId().Text, Scope = scopeName.ToString(), ScopeLevel = scopeLevel, DataType = node.GetType().ToString().Trim() });
            else _exceptionList.Add(new SemanticException(String.Format("Id: {0} already exsists. Line:{1}, pos:{2}", node.GetId(), node.GetId().Line, node.GetId().Pos)));
        }
        #endregion

        #region cStruct
        public override void CaseACstructBody(ACstructBody node)
        {
            ++scopeLevel;
            base.CaseACstructBody(node);
            SymbolTable.RemoveVariableFromScopeLevel(scopeLevel);
            --scopeLevel;
        }
        #region if&while
        /// <summary>
        /// Manages typechecking for If header. Initiates semantic analysis of body subtree
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAIfBody(AIfBody node)
        {
            node.GetExpressionOpt().Apply(this);
            if (node.GetExpressionOpt().NodeType != "bool" && node.GetExpressionOpt().NodeType != null)
                _exceptionList.Add(new SemanticException(string.Format("If predicate not a bool, line:{0} pos:{1}",
                    node.GetTThen().Line, node.GetTThen().Pos)));
            node.GetBodyList().Apply(this);

            node.GetElse().Apply(this);

        }
        public override void CaseAWhile(AWhile node)
        {
            node.GetExpressionOpt().Apply(this);
            if (node.GetExpressionOpt().NodeType != "bool" && node.GetExpressionOpt().NodeType != null)
                _exceptionList.Add(new SemanticException(string.Format("While predicate not a bool, line:{0} pos:{1}",
                    node.GetTWhile().Line, node.GetTWhile().Pos)));

            node.GetBodyList().Apply(this);
        }
        #endregion
        #region for
        /// <summary>
        /// Manages typechecking for For header. Initiates semantic analysis of body subtree
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAFor(AFor node)
        {

            node.GetCounterId().Apply(this);
            node.GetForTo().Apply(this);
            POffset offset = node.GetOffset();
            if (offset is AExprOffset) //If offset is AEmptyOffset we dont care about it in the semanticanalysis
            {
                AExprOffset exprOffset = (AExprOffset)offset;
                exprOffset.GetConditionalExp().Apply(this);
                if (exprOffset.GetConditionalExp().NodeType != "int")
                    _exceptionList.Add(new SemanticException(string.Format("Offset expression must be an int value, line:{0} pos:{1}",
                        exprOffset.GetTOffset().Line, exprOffset.GetTOffset().Pos)));

            }
            node.GetBodyList().Apply(this);
        }

        /// <summary>
        /// Adds counter id to current scope
        /// </summary>
        /// <param name="node"></param>
        public override void CaseADeclIdCounterId(ADeclIdCounterId node)
        {
            SymbolTable.Add(new VariableEntry() { Id = node.GetId().Text, DataType = "int", Scope = scopeName, ScopeLevel = scopeLevel });
        }
        /// <summary>
        /// Typecheck counter id, needs to be int
        /// </summary>
        /// <param name="node"></param>
        public override void CaseACounterId(ACounterId node)
        {
            string idType = "";
            try
            {
                VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopeName, scopeLevel);
                idType = ve.DataType;
            }
            catch (SymbolTableException e)
            {
                AFor parentNode = (AFor)node.Parent(); //To pin point error for user
                _exceptionList.Add(new SemanticException(string.Format("{0} doesn't exist in the current context, Line:{1} pos:{2}",
                    node.GetId().Text, parentNode.GetTFor().Line, parentNode.GetTFor().Pos)));
            }


            if (idType != "int" && idType != "") //empty is so that we dont throw unnescary errors
            {
                AFor parentNode = (AFor)node.Parent(); //To pin point error for user
                _exceptionList.Add(new SemanticException(string.Format("Counter id has to be an int, line:{0} pos:{1}",
                    parentNode.GetTFor().Line, parentNode.GetTFor().Pos)));
            }
        }
        /// <summary>
        /// Typecheck down_to id, needs to be int
        /// </summary>
        /// <param name="node"></param>
        public override void CaseADIdForTo(ADIdForTo node)
        {
            string idType = "";
            try
            {
                VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopeName, scopeLevel);
                idType = ve.DataType;
            }
            catch (SymbolTableException e)
            {
                AFor parentNode = (AFor)node.Parent(); //To pin point error for user
                _exceptionList.Add(new SemanticException(string.Format("{0} doesn't exist in the current context, Line:{1} pos:{2}",
                    node.GetId().Text, parentNode.GetTFor().Line, parentNode.GetTFor().Pos)));
            }

            if (idType != "int" && idType != "")
            {
                AFor parentNode = (AFor)node.Parent(); //To pin point error for user
                _exceptionList.Add(new SemanticException(string.Format("Counter id has to be an int, line:{0} pos:{1}",
                    parentNode.GetTFor().Line, parentNode.GetTFor().Pos)));
            }
        }
        /// <summary>
        /// Typecheck up_to id, needs to be int
        /// </summary>
        /// <param name="node"></param>
        public override void CaseAUIdForTo(AUIdForTo node)
        {
            string idType = "";
            try
            {
                VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopeName, scopeLevel);
                idType = ve.DataType;
            }
            catch (SymbolTableException e)
            {
                AFor parentNode = (AFor)node.Parent(); //To pin point error for user
                _exceptionList.Add(new SemanticException(string.Format("{0} doesn't exist in the current context, Line:{1} pos:{2}",
                    node.GetId().Text, parentNode.GetTFor().Line, parentNode.GetTFor().Pos)));
            }
            if (idType != "int")
            {
                AFor parentNode = (AFor)node.Parent(); //To pin point error for user
                _exceptionList.Add(new SemanticException(string.Format("Counter id has to be an int, line:{0} pos:{1}",
                                                            parentNode.GetTFor().Line, parentNode.GetTFor().Pos)));
            }
        }
        #endregion
        #region switch
        public override void CaseASwitch(ASwitch node)
        {
            node.GetScalar().Apply(this);
            node.NodeType = node.GetScalar().NodeType;
            node.GetCases().Apply(this);
        }
        public override void CaseARecurvCaseCases(ARecurvCaseCases node)
        {
            node.NodeType = node.Parent().NodeType; //inherit type from switch(parent node) so that we have easier access to it in the case nodes
            base.CaseARecurvCaseCases(node);
        }
        public override void CaseACase(ACase node)
        {
            if (!(node.GetScalar() is AIdScalar))
            {
                node.GetScalar().Apply(this);
                if (node.GetScalar().NodeType != node.Parent().NodeType)
                    _exceptionList.Add(new SemanticException(string.Format("Cant switch on two different types, line:{0} pos:{1}",
                        node.GetTCase().Line, node.GetTCase().Pos)));
                node.GetBodyList().Apply(this);
            }
            else
                _exceptionList.Add(new SemanticException(string.Format("Cant case-switch on an identifier needs to be a literal value, line:{0} pos:{1}",
                        node.GetTCase().Line, node.GetTCase().Pos)));
        }
        #endregion
        #endregion

        #region expressionTypeChecking
        public override void OutAReturnBody(AReturnBody node)
        {
            try
            {
                VariableEntry ve = (VariableEntry)SymbolTable.Find(scopeName, scopes.Functions.ToString());
                if (ve.DataType != "function")
                {
                    if (node.GetExpressionOpt() is AExpressionOpt)
                    {
                        if (ve.DataType != "void")
                        {
                            _exceptionList.Add(new SemanticException(string.Format("Expecting to return type {0} trying to return {1}, Line:{2} pos:{3}",
                                                        ve.DataType, "void", node.GetTReturn().Line, node.GetTReturn().Pos)));
                        }
                    }
                    else if (ve.DataType != node.GetExpressionOpt().NodeType)
                    {
                        _exceptionList.Add(new SemanticException(string.Format("Expecting to return type {0} trying to return {1}, Line:{2} pos:{3}",
                            ve.DataType, node.GetExpressionOpt().NodeType, node.GetTReturn().Line, node.GetTReturn().Pos)));
                    }
                }
                else
                    _exceptionList.Add(new SemanticException(string.Format("Expecting no return, Line:{2} pos:{3}",
                            ve.DataType, node.GetExpressionOpt().NodeType, node.GetTReturn().Line, node.GetTReturn().Pos)));
                if (scopeLevel != 0)
                    ve.NumericValue = false;
                else
                    ve.NumericValue = true;
            }
            catch (SymbolTableException e)
            {
                _exceptionList.Add(new SemanticException(string.Format("Trying to return outside a function, Line:{0} pos:{1}",
                    node.GetTReturn().Line, node.GetTReturn().Pos)));
            }
        }
        public override void OutAAddKeyDefinationBody(AAddKeyDefinationBody node)
        {
            if (node.GetConditionalExp().BaseNode != "assign" && node.GetConditionalExp().BaseNode != "functionCall")
                _exceptionList.Add(new SemanticException(string.Format("Assigning to a key needs to involve an assignment or a function call, Line:{0} pos:{0}",
                    node.GetTKey().Line, node.GetTKey().Pos)));
            else
                keyEventListeneres.Add(node.GetConditionalExp().ToString().Replace(" ", ""));
            base.OutAAddKeyDefinationBody(node);
        }
       
        public override void OutAExprBody(AExprBody node)
        {
            SemanticException se = new SemanticException(string.Format("{2} cant have an empty statement, Line:{0} pos:{1}",
                node.GetEndline().Line, node.GetEndline().Pos, node.GetExpression().BaseNode));
            switch (node.GetExpression().BaseNode)
            {
                case "functionCall": break;
                case "assign": break;
                default:
                    _exceptionList.Add(se);
                    break;
            }
            base.OutAExprBody(node);
        }
        #region typeChecking
        #region AssignExpressions
        public override void OutAAssignExpression(AAssignExpression node)
        {
            node.BaseNode = "assign";
            node.NodeType = node.GetExpression().NodeType;

            if (node.GetScalar().BaseNode == "id" || node.GetScalar().BaseNode == "entity")
            {
                string leftExp = node.GetScalar().NodeType;
                string rightExp = node.GetExpression().NodeType;

                string type;
                if (leftExp == "string" && rightExp == "string")
                    type = "string";
                else if (leftExp == "coord" && rightExp == "coord")
                    type = "coord";
                else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                    _exceptionList.Add(new SemanticException(string.Format("Cant assign {1} to {0}. Line:{2}, pos:{3}",
                                               leftExp, rightExp, node.GetAsign().Line, node.GetAsign().Pos)));

                node.Parent().NodeType = node.NodeType = type;
            }
            else
                _exceptionList.Add(new SemanticException(string.Format("Cant assign to a typeliteral, Line:{3}, pos{4}", node.GetAsign().Line, node.GetAsign().Pos)));
        }

        public override void OutAAssignAddExpression(AAssignAddExpression node)
        {
            node.BaseNode = "assign";
            node.NodeType = node.GetExpression().NodeType;

            if (node.GetScalar().BaseNode == "id" || node.GetScalar().BaseNode == "entity")
            {
                string leftExp = node.GetScalar().NodeType;
                string rightExp = node.GetExpression().NodeType;

                string type;
                if (leftExp == "string" && rightExp == "string")
                    type = "string";
                else if (leftExp == "coord" && rightExp == "coord")
                    type = "coord";
                else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                    _exceptionList.Add(new SemanticException(string.Format("Cant assign {1} to {0}. Line:{2}, pos:{3}",
                                               leftExp, rightExp, node.GetAsignAdd().Line, node.GetAsignAdd().Pos)));

                node.Parent().NodeType = node.NodeType = type;
            }
            else
                _exceptionList.Add(new SemanticException(string.Format("Cant assign to a typeliteral, Line:{0}, pos{1}", node.GetAsignAdd().Line, node.GetAsignAdd().Pos)));
        }

        public override void OutAAssignSubExpression(AAssignSubExpression node)
        {
            node.BaseNode = "assign";
            node.NodeType = node.GetExpression().NodeType;

            if (node.GetScalar().BaseNode == "id" || node.GetScalar().BaseNode == "entity")
            {
                string leftExp = node.GetScalar().NodeType;
                string rightExp = node.GetExpression().NodeType;

                string type;
                if (leftExp == "string" && rightExp == "string")
                    type = "string";
                else if (leftExp == "coord" && rightExp == "coord")
                    type = "coord";
                else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                    _exceptionList.Add(new SemanticException(string.Format("Cant assign {1} to {0}. Line:{2}, pos:{3}",
                                               leftExp, rightExp, node.GetAsignSub().Line, node.GetAsignSub().Pos)));

                node.Parent().NodeType = node.NodeType = type;
            }
            else
                _exceptionList.Add(new SemanticException(string.Format("Cant assign to a typeliteral, Line:{3}, pos{4}", node.GetAsignSub().Line, node.GetAsignSub().Pos)));
        }

        public override void OutAAssignMultExpression(AAssignMultExpression node)
        {
            node.BaseNode = "assign";
            node.NodeType = node.GetExpression().NodeType;

            if (node.GetScalar().BaseNode == "id" || node.GetScalar().BaseNode == "entity")
            {
                string leftExp = node.GetScalar().NodeType;
                string rightExp = node.GetExpression().NodeType;

                string type;
                if (leftExp == "coord" && rightExp == "coord")
                    type = "coord";
                else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                    _exceptionList.Add(new SemanticException(string.Format("Cant assign {1} to {0}. Line:{2}, pos:{3}",
                                               leftExp, rightExp, node.GetAsignMult().Line, node.GetAsignMult().Pos)));

                node.Parent().NodeType = node.NodeType = type;
            }
            else
                _exceptionList.Add(new SemanticException(string.Format("Cant assign to a typeliteral, Line:{3}, pos{4}", node.GetAsignMult().Line, node.GetAsignMult().Pos)));

        }

        public override void OutAAssignDivideExpression(AAssignDivideExpression node)
        {
            node.BaseNode = "assign";
            node.NodeType = node.GetExpression().NodeType;

            if (node.GetScalar().BaseNode == "id" || node.GetScalar().BaseNode == "entity")
            {
                string leftExp = node.GetScalar().NodeType;
                string rightExp = node.GetExpression().NodeType;

                string type;
                if (leftExp == "coord" && rightExp == "coord")
                    type = "coord";
                else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                    _exceptionList.Add(new SemanticException(string.Format("Cant assign {1} to {0}. Line:{2}, pos:{3}",
                                               leftExp, rightExp, node.GetAsignDivide().Line, node.GetAsignDivide().Pos)));

                node.Parent().NodeType = node.NodeType = type;
            }
            else
                _exceptionList.Add(new SemanticException(string.Format("Cant assign to a typeliteral, Line:{3}, pos{4}", node.GetAsignDivide().Line, node.GetAsignDivide().Pos)));

        }

        public override void OutAAssignModExpression(AAssignModExpression node)
        {
            node.BaseNode = "assign";
            node.NodeType = node.GetExpression().NodeType;

            if (node.GetScalar().BaseNode == "id" || node.GetScalar().BaseNode == "entity")
            {
                string leftExp = node.GetScalar().NodeType;
                string rightExp = node.GetExpression().NodeType;

                string type;
                if (leftExp == "coord" && rightExp == "coord")
                    type = "coord";
                else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                    _exceptionList.Add(new SemanticException(string.Format("Cant assign {1} to {0}. Line:{2}, pos:{3}",
                                               leftExp, rightExp, node.GetAsignMod().Line, node.GetAsignMod().Pos)));

                node.Parent().NodeType = node.NodeType = type;
            }
            else
                _exceptionList.Add(new SemanticException(string.Format("Cant assign to a typeliteral, Line:{3}, pos{4}", node.GetAsignMod().Line, node.GetAsignMod().Pos)));

        }
        #endregion

        #region conditional
        /// <summary>
        /// checks that the condition is a bool, then checks the true/flase expression for type
        /// </summary>
        /// <param name="node"></param>
        public override void OutACondConditionalExp(ACondConditionalExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.GetR().NodeType; //since the two conditional expressions have to evaluate to the same type, passing one type up is enough

            if (node.GetL().NodeType != "bool") //Checks that the condition is evaluated to a bool
                _exceptionList.Add(new SemanticException(string.Format("Conditional not a bool type-value. Line:{0}, pos:{1}", node.GetOpIf().Line, node.GetOpIf().Pos)));

            if (node.GetR().NodeType != node.GetConditionalExp().NodeType) //checks that the two conditional expressions are the same type
                _exceptionList.Add(new SemanticException(string.Format("Do if expressions aren't the same type, thus isnt valid. Line:{0}, pos{1}", node.GetOpDo().Line, node.GetOpDo().Pos)));
        }
        #endregion

        #region or
        public override void OutAOrOrExp(AOrOrExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetOrExp().NodeType;
            string rightExp = node.GetAndExp().NodeType;

            if (leftExp != "bool" && leftExp != "bool")
                _exceptionList.Add(new SemanticException(string.Format("Can only compare boolean expressions with Or, tried to compare {0} and {1}. Line:{2}, pos:{3}",
                        node.GetOrExp().NodeType, node.GetAndExp().NodeType, node.GetBoolOr().Line, node.GetBoolOr().Pos)));
        }
        #endregion

        #region and
        public override void OutAAndAndExp(AAndAndExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetAndExp().NodeType;
            string rightExp = node.GetEqualityExp().NodeType;

            if (leftExp != "bool" && leftExp != "bool")
                _exceptionList.Add(new SemanticException(string.Format("Can only compare boolean expressions with and, tried to compare {0} and {1}. Line:{2}, pos:{3}",
                 node.GetAndExp().NodeType, node.GetEqualityExp().NodeType, node.GetBoolAnd().Line, node.GetBoolAnd().Pos)));
        }
        #endregion

        #region equality
        public override void OutAEqualEqualityExp(AEqualEqualityExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetEqualityExp().NodeType;
            string rightExp = node.GetCompareExp().NodeType;
            string i; //arithmetic returns a type apropriate for arithmetic operations, we arent interested in that

            if (leftExp != rightExp) //compares the types of two sub-expressions
                if (!ArithmeticTypeCheck(leftExp, rightExp, out i))
                    _exceptionList.Add(new SemanticException(string.Format("Cant compare two different types , tried to compare {0} and {1}. Line:{2}, pos:{3}",
                        node.GetEqualityExp().NodeType, node.GetCompareExp().NodeType, node.GetBoolEqual().Line, node.GetBoolEqual().Pos)));
        }
        public override void OutANotEqualEqualityExp(ANotEqualEqualityExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetEqualityExp().NodeType;
            string rightExp = node.GetCompareExp().NodeType;
            string i; //arithmetic returns a type apropiate for arithmetic operations, we arent interested in that

            if (leftExp != rightExp) //compares the types of two sub-expressions
                if (!ArithmeticTypeCheck(leftExp, rightExp, out i))
                    _exceptionList.Add(new SemanticException(string.Format("Cant compare two different types , tried to compare {0} and {1}. Line:{2}, pos:{3}",
                        node.GetEqualityExp().NodeType, node.GetCompareExp().NodeType, node.GetBoolNotEqual().Line, node.GetBoolNotEqual().Pos)));
        }
        #endregion

        #region compare
        public override void OutALesserCompareExp(ALesserCompareExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetCompareExp().NodeType;
            string rightExp = node.GetAddExp().NodeType;
            string i; //arithmetic returns a type apropiate for arithmetic operations, we arent interested in that

            if(leftExp == "coord" || rightExp == "coord")
                _exceptionList.Add(new SemanticException(string.Format("Cant compare two coords. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolLesser().Line, node.GetBoolLesser().Pos)));
            else if (leftExp != rightExp) //compares the types of two sub-expressions
                if (!ArithmeticTypeCheck(leftExp, rightExp, out i))
                    _exceptionList.Add(new SemanticException(string.Format("Cant compare two different types with lesser than operator, tried to compare {0} and {1}. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolLesser().Line, node.GetBoolLesser().Pos)));
        }
        public override void OutAGreaterCompareExp(AGreaterCompareExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetCompareExp().NodeType;
            string rightExp = node.GetAddExp().NodeType;
            string i; //arithmetic returns a type apropiate for arithmetic operations, we arent interested in that

            if (leftExp == "coord" || rightExp == "coord")
                _exceptionList.Add(new SemanticException(string.Format("Cant compare two coords. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolGreater().Line, node.GetBoolGreater().Pos)));
            else if (leftExp != rightExp) //compares the types of two sub-expressions
                if (!ArithmeticTypeCheck(leftExp, rightExp, out i))
                    _exceptionList.Add(new SemanticException(string.Format("Cant compare two different types with greater than operator, tried to compare {0} and {1}. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolGreater().Line, node.GetBoolGreater().Pos)));
        }
        public override void OutAEqualOrLCompareExp(AEqualOrLCompareExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetCompareExp().NodeType;
            string rightExp = node.GetAddExp().NodeType;
            string i; //arithmetic returns a type apropiate for arithmetic operations, we arent interested in that

            if (leftExp == "coord" || rightExp == "coord")
                _exceptionList.Add(new SemanticException(string.Format("Cant compare two coords. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolEqualOrL().Line, node.GetBoolEqualOrL().Pos)));
            else if (leftExp != rightExp) //compares the types of two sub-expressions
                if (!ArithmeticTypeCheck(leftExp, rightExp, out i))
                    _exceptionList.Add(new SemanticException(string.Format("Cant compare two different types with lesser than or equal operator, tried to compare {0} and {1}. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolEqualOrL().Line, node.GetBoolEqualOrL().Pos)));
        }
        public override void OutAEqualOrGCompareExp(AEqualOrGCompareExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool"; //this expression is always evaluated to a bool

            string leftExp = node.GetCompareExp().NodeType;
            string rightExp = node.GetAddExp().NodeType;
            string i; //arithmetic returns a type apropiate for arithmetic operations, we arent interested in that

            if (leftExp == "coord" || rightExp == "coord")
                _exceptionList.Add(new SemanticException(string.Format("Cant compare two coords. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolEqualOrG().Line, node.GetBoolEqualOrG().Pos)));
            else if (leftExp != rightExp) //compares the types of two sub-expressions
                if (!ArithmeticTypeCheck(leftExp, rightExp, out i))
                    _exceptionList.Add(new SemanticException(string.Format("Cant compare two different types with greater than or equal operator, tried to compare {0} and {1}. Line:{2}, pos:{3}",
                        node.GetCompareExp().NodeType, node.GetAddExp().NodeType, node.GetBoolEqualOrG().Line, node.GetBoolEqualOrG().Pos)));
        }
        #endregion

        #region add
        public override void OutAAddAddExp(AAddAddExp node)
        {
            node.BaseNode = "expression";
            string leftExp = node.GetAddExp().NodeType;
            string rightExp = node.GetMultExp().NodeType;

            string type;
            if (leftExp == "string" && rightExp == "string")
                type = "string";
            else if (leftExp == "coord" && rightExp == "coord")
                type = "coord";
            else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                _exceptionList.Add(new SemanticException(string.Format("Cant add {0} and {1}. Line:{2}, pos:{3}",
                                           leftExp, rightExp, node.GetArthAdd().Line, node.GetArthAdd().Pos)));

            node.Parent().NodeType = node.NodeType = type;
        }
        public override void OutASubAddExp(ASubAddExp node)
        {
            node.BaseNode = "expression";
            string leftExp = node.GetAddExp().NodeType;
            string rightExp = node.GetMultExp().NodeType;

            string type;

            if (leftExp == "coord" && leftExp == "coord")
                type = "coord";
            else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                _exceptionList.Add(new SemanticException(string.Format("Cant subtract {0} and {1}. Line:{2}, pos:{3}",
                                           leftExp, rightExp, node.GetArthSub().Line, node.GetArthSub().Pos)));

            node.Parent().NodeType = node.NodeType = type;
        }
        #endregion

        #region mult
        public override void OutAMultMultExp(AMultMultExp node)
        {
            node.BaseNode = "expression";
            string leftExp = node.GetMultExp().NodeType;
            string rightExp = node.GetUnaryExp().NodeType;

            string type;

            if (leftExp == "coord" && leftExp == "coord")
                type = "coord";
            else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                _exceptionList.Add(new SemanticException(string.Format("Cant multiply {0} and {1}. Line:{2}, pos:{3}",
                                           leftExp, rightExp, node.GetArthMult().Line, node.GetArthMult().Pos)));

            node.Parent().NodeType = node.NodeType = type;

        }
        public override void OutADivideMultExp(ADivideMultExp node)
        {
            node.BaseNode = "expression";
            string leftExp = node.GetMultExp().NodeType;
            string rightExp = node.GetUnaryExp().NodeType;

            string type;

            if (leftExp == "coord" && leftExp == "coord")
                type = "coord";
            else if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                _exceptionList.Add(new SemanticException(string.Format("Cant divide {0} and {1}. Line:{2}, pos:{3}",
                    leftExp, rightExp, node.GetArthDivide().Line, node.GetArthDivide().Pos)));

            node.Parent().NodeType = node.NodeType = type;
        }
        public override void OutAModMultExp(AModMultExp node)
        {
            node.BaseNode = "expression";
            string leftExp = node.GetMultExp().NodeType;
            string rightExp = node.GetUnaryExp().NodeType;

            string type;

            if (!ArithmeticTypeCheck(leftExp, rightExp, out type))
                _exceptionList.Add(new SemanticException(string.Format("Cant multiply {0} and {1}. Line:{2}, pos:{3}",
                                           leftExp, rightExp, node.GetArthMod().Line, node.GetArthMod().Pos)));
            node.Parent().NodeType = node.NodeType = type;
        }
        #endregion

        /// <summary>
        /// Type checks arthimitic expressions (ie. where left and right expressions needs to be a numeric value)
        /// </summary>
        /// <param name="leftExp"></param>
        /// <param name="rightExp"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool ArithmeticTypeCheck(string leftExp, string rightExp, out string type)
        {
            string i = "";
            switch (leftExp) //Compares the rightExp type to the leftExp type
            {
                case "float": //if leftExp is a float, the type is float regardless of what the rightExp is
                    type = "float"; //Passes up type info
                    if (rightExp != "float" && rightExp != "int") //checks if rightExp is a valid type for multiplication
                    {
                        type = rightExp;
                        return false;
                    }
                    break;
                case "int": //if leftExp is an int we need to check rightExp for valid type, and if its float pass up float instead of int
                    if (rightExp == "float")
                        type = "float"; //Passes up type info
                    else
                        type = "int"; //Passes up type info
                    if (rightExp != "float" && rightExp != "int") //checks if rightExp is a valid type for multiplication
                    {
                        type = rightExp;
                        return false;
                    }
                    break;
                default:
                    type = leftExp;
                    return false;
            }
            return true;
        }

        #region unary
        public override void OutANotUnaryExp(ANotUnaryExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType = "bool";
            if (node.GetUnaryExp().NodeType != "bool") //Can only use operator on bool
                _exceptionList.Add(new SemanticException(string.Format("Can only apply not to bool, tried to apply to {0}. Line:{1}, pos:{2}",
                    node.GetUnaryExp().NodeType, node.GetUnNot().Line, node.GetUnNot().Pos)));
        }
        public override void OutANegateUnaryExp(ANegateUnaryExp node)
        {
            node.BaseNode = "expression";
            node.Parent().NodeType = node.NodeType;
            if (node.GetUnaryExp().NodeType != "int" && node.GetUnaryExp().NodeType != "float") //Can only use operator on int or float. Therefore if expression isn't either we throw an exception
                _exceptionList.Add(new SemanticException(string.Format("Can only apply negate to int or float, tried to apply a {0}. Line:{1}, pos:{2}",
                    node.GetUnaryExp().NodeType, node.GetArthSub().Line, node.GetArthSub().Pos)));
        }
        public override void OutAIncrementUnaryExp(AIncrementUnaryExp node)
        {
            node.Parent().BaseNode = node.BaseNode = "assign";
            node.Parent().NodeType = node.NodeType;
            if (node.GetUnaryExp().NodeType != "int" && node.GetUnaryExp().NodeType != "float") //Can only use operator on int or float. Therefore if expression isn't either we throw an exception
                _exceptionList.Add(new SemanticException(string.Format("Can only increment int or float, tried to increment a {0}. Line:{1}, pos:{2}",
                    node.GetUnaryExp().NodeType, node.GetUnIncrement().Line, node.GetUnIncrement().Pos)));
        }
        public override void OutADecrementUnaryExp(ADecrementUnaryExp node)
        {
            node.Parent().BaseNode = node.BaseNode = "assign";
            node.Parent().NodeType = node.NodeType;
            if (node.GetUnaryExp().NodeType != "int" && node.GetUnaryExp().NodeType != "float") //Can only use operator on int or float. Therefore if expression isn't either we throw an exception
                _exceptionList.Add(new SemanticException(string.Format("Can only decrement int or float, tried to decrement a {0}. Line:{1}, pos:{2}",
                    node.GetUnaryExp().NodeType, node.GetUnDecrement().Line, node.GetUnDecrement().Pos)));
        }
        #endregion
        #endregion

        #region passUpTypeInfo
        //Type is just passed up to the top, if it is never used in type checking it just gets passed up to expression_opt. if at any time it gets an invalid typecheck the compiler exists and its never used
        //thus even though the type information is passed up no matter what, if it is invovled in a 
        #region Productions
        public override void OutAExpression(AExpression node)
        {

            node.Parent().NodeType = node.NodeType; //passes type upwards to expression_opt which is probably never used, keep?            
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutAConditionalExp(AConditionalExp node)
        {
            node.Parent().BaseNode = node.BaseNode;
            node.Parent().NodeType = node.NodeType;
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutAOrExp(AOrExp node)
        {
            node.Parent().BaseNode = node.BaseNode;
            node.Parent().NodeType = node.NodeType;
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutAAndExp(AAndExp node)
        {
            node.Parent().BaseNode = node.BaseNode;
            node.Parent().NodeType = node.NodeType;
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutAEqualityExp(AEqualityExp node)
        {
            node.Parent().BaseNode = node.BaseNode;
            node.Parent().NodeType = node.NodeType;
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutACompareExp(ACompareExp node)
        {
            node.Parent().BaseNode = node.BaseNode; ;
            node.Parent().NodeType = node.NodeType;
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutAAddExp(AAddExp node)
        {
            node.Parent().BaseNode = node.BaseNode;
            node.Parent().NodeType = node.NodeType;
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutAMultExp(AMultExp node)
        {
            node.Parent().BaseNode = node.BaseNode;
            node.Parent().NodeType = node.NodeType;
        }
        /// <summary>
        /// passes type upwards
        /// </summary>
        /// <param name="node"></param>
        public override void OutAUnaryExp(AUnaryExp node)
        {
            node.Parent().BaseNode = node.BaseNode;
            node.Parent().NodeType = node.NodeType;
        }

        #endregion

        /// <summary>
        /// initializse types - still no way to cast types. I.e. no logic to decide which is sent further up (float+int)?
        /// </summary>
        /// <param name="node"></param>
        #region typeLiterals
        public override void OutAIntScalar(AIntScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "int";
            node.Parent().NodeType = node.NodeType = "int";
        }
        public override void OutAFloatScalar(AFloatScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "float";
            node.Parent().NodeType = node.NodeType = "float";
        }
        public override void OutABoolScalar(ABoolScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "bool";
            node.Parent().NodeType = node.NodeType = "bool";
        }
        public override void OutAStringScalar(AStringScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "string";
            node.Parent().NodeType = node.NodeType = "string";
        }
        public override void OutACharScalar(ACharScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "char";
            node.Parent().NodeType = node.NodeType = "char";
        }
        public override void OutACoordScalar(ACoordScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "coord";
            node.Parent().NodeType = node.NodeType = "coord";
        }
        public override void OutACoordliteral(ACoordliteral node)
        {
            node.Parent().BaseNode = node.BaseNode = "coord";
            string lExprType = node.GetLExpression().NodeType;
            string rExprType = node.GetRExpression().NodeType;

            if (lExprType != "int" && lExprType != "float")
            {
                _exceptionList.Add(new SemanticException(string.Format("Coord contains an invalid type {0} as the left argument, line:{1} pos:{2}",
                    lExprType, node.GetOParenth().Line, node.GetOParenth().Pos)));
            }
            if (rExprType != "int" && rExprType != "float")
                _exceptionList.Add(new SemanticException(string.Format("Coord contains an invalid type {0} as the right argument, line:{1} pos:{2}",
                    rExprType, node.GetOParenth().Line, node.GetOParenth().Pos)));
        }
        public override void OutAIdScalar(AIdScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "id";
            if (SymbolTable.VariableExists(node.GetId().Text, scopeName, scopeLevel))
            {
                VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopeName, scopeLevel);
                node.Parent().NodeType = node.NodeType = ve.DataType;
            }
            else if (SymbolTable.VariableExists(node.GetId().Text, scopes.Functions.ToString(), 0))
            {
                VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopes.Functions.ToString());
                if (ve.DataType == "templates")
                    node.Parent().NodeType = node.NodeType = ve.DataType;
                else
                    _exceptionList.Add(new SemanticException(String.Format("{0} cant be used as a varialbe. Line:{1}, pos{2}", node.GetId(), node.GetId().Line, node.GetId().Pos)));
            }
            else
            {
                _exceptionList.Add(new SemanticException(String.Format("{0} is used but never declared. Line:{1}, pos{2}", node.GetId(), node.GetId().Line, node.GetId().Pos)));
            }
        }
        public override void OutAEntityMemberAccessScalar(AEntityMemberAccessScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "entity";
            try
            {
                VariableEntry templateVe = (VariableEntry)SymbolTable.Find(node.GetTemplate().Text, scopeName, scopeLevel);
                if (templateVe.DataType == "coord")
                {
                    if (node.GetMember().Text.ToLower() == "x" || node.GetMember().Text.ToLower() == "y")
                        node.Parent().NodeType = node.NodeType = "float";
                }
                else
                {
                    VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetMember().Text, templateVe.DataType);

                    node.Parent().NodeType = node.NodeType = ve.DataType;
                }
            }
            catch (SymbolTableException e)
            {
                _exceptionList.Add(new SemanticException(string.Format("{0}, Line:{1} pos:{2}", e.Message, node.GetTDot().Line, node.GetTDot().Pos)));
            }
            //}
        }
        public override void OutAExpParenthScalar(AExpParenthScalar node)
        {
            node.Parent().NodeType = node.NodeType = node.GetExpression().NodeType;
            node.BaseNode = node.Parent().BaseNode = node.GetExpression().BaseNode;
        }
        #region functionCalls

        public override void CaseAEmptyFunctionCallScalar(AEmptyFunctionCallScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "functionCall";
            //check if function with node.id expects zero params
            try
            {
                VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopes.Functions.ToString());
                node.Parent().NodeType = node.NodeType = ve.DataType; // //return value for the function
                if (ve.ParamCount != 0)
                    _exceptionList.Add(new SemanticException(string.Format("Missing parameters expecting {2}, Line:{0} pos:{1}",
                        node.GetOParenth().Line, node.GetOParenth().Pos, ve.ParamCount)));
            }
            catch (SymbolTableException e)
            {
                if (isDraw)
                {
                    VariableEntry ve = drawFunctions.Find(x => x.Id == node.GetId().Text);
                    if (ve != null)
                    {
                        node.Parent().NodeType = node.NodeType = ve.DataType; // //return value for the function
                        if (ve.ParamCount != 0)
                            _exceptionList.Add(new SemanticException(string.Format("Missing parameters expecting {2}, Line:{0} pos:{1}",
                                node.GetOParenth().Line, node.GetOParenth().Pos, ve.ParamCount)));
                    }
                    else
                        _exceptionList.Add(new SemanticException(string.Format("Id doesnt exist, Line:{0} pos:{1}", node.GetOParenth().Line, node.GetOParenth().Pos)));
                }
                else
                    _exceptionList.Add(new SemanticException(string.Format("Id doesnt exist, Line:{0} pos:{1}", node.GetOParenth().Line, node.GetOParenth().Pos)));
            }
        }

        public override void CaseAFunctionCallScalar(AFunctionCallScalar node)
        {
            node.Parent().BaseNode = node.BaseNode = "functionCall";
            try
            {
                node.NodeType = node.GetId().Text;
                //setup data collection for params. They will be gathered in reverse ie. id(int, float) will be float,int. So use a stack?
                //note empty function call have seperate function
                node.GetExpressionSequnece().Apply(this);
                VariableEntry ve = (VariableEntry)SymbolTable.Find(node.GetId().Text, scopes.Functions.ToString());
                if (ve.ParamQueueCount != 0)
                    _exceptionList.Add(new SemanticException(string.Format("Number of parameters doesnt match, expected {0}. Line:{1} Pos:{2}",
                        ve.ParamCount, node.GetOParenth().Line, node.GetOParenth().Pos)));
                node.Parent().NodeType = node.NodeType = ve.DataType; // //return value for the function
                ve.ParamReset();
            }
            catch (SymbolTableException e)
            {
                if (isDraw)
                {
                    try
                    {
                        VariableEntry ve = drawFunctions.Find(x => x.Id == node.GetId().Text);
                        if (ve != null)
                        {
                            if (ve.ParamQueueCount != 0)
                                _exceptionList.Add(new SemanticException(string.Format("Number of parameters doesnt match, expected {0}. Line:{1} Pos:{2}",
                                    ve.ParamCount, node.GetOParenth().Line, node.GetOParenth().Pos)));
                            node.Parent().NodeType = node.NodeType = ve.DataType; // //return value for the function
                            ve.ParamReset();
                        }
                        else
                            _exceptionList.Add(new SemanticException(string.Format("Function doesnt exist, Line:{0} pos:{1}", node.GetOParenth().Line, node.GetOParenth().Pos)));
                    }
                    catch (ArgumentNullException eDraw)
                    {
                        _exceptionList.Add(new SemanticException(string.Format("Function doesnt exist, Line:{0} pos:{1}", node.GetOParenth().Line, node.GetOParenth().Pos)));
                    }
                }
                else
                    _exceptionList.Add(new SemanticException(string.Format("Function doesnt exist, Line:{0} pos:{1}", node.GetOParenth().Line, node.GetOParenth().Pos)));
            }

        }

        public override void CaseAMultipleExpressionSequnece(AMultipleExpressionSequnece node)
        {
            node.NodeType = node.Parent().NodeType;
            string temp = node.NodeType;
            string temp2; //omfg

            VariableEntry ve;
            try
            {
                ve = (VariableEntry)SymbolTable.Find(node.Parent().NodeType, scopes.Functions.ToString());
            }
            catch (SymbolTableException e)
            {
                ve = (VariableEntry)drawFunctions.Find(x => x.Id == node.Parent().NodeType);
            }

            if (ve.ParamQueueCount < 1)
                _exceptionList.Add(new SemanticException(string.Format("Number of parameters doesnt match, expected {0}. Line:{1} Pos:{2}",
                    ve.ParamCount, node.GetComma().Line, node.GetComma().Pos)));
            else
            {
                //changed
                VariableEntry formalParam = (VariableEntry)ve.ParamPeek();


                if (formalParam.DataType == "List")
                {
                    node.GetExpression().Apply(this);
                    formalParam = (VariableEntry)ve.ParamDequeue(false);
                    VariableEntry secondParam = (VariableEntry)ve.ParamDequeue(true);
                    secondParam.DataType = node.NodeType = node.GetExpression().NodeType.Replace("List", "");
                    formalParam.DataType = node.GetExpression().NodeType;
                    ve.ParamEnqueue(secondParam);
                    if (ve.Id == "ListGet")
                    {
                        ve.DataType = secondParam.DataType;
                    }
                    else if (ve.Id == "ListRemove")
                        ve.DataType = "bool"; //Set return type
                    temp2 = node.NodeType;
                    node.NodeType = node.Parent().NodeType = temp;
                    node.GetExpressionSequnece().Apply(this);
                    node.NodeType = node.Parent().NodeType = temp2;

                }
                else
                {

                    formalParam = (VariableEntry)ve.ParamDequeue(false);
                    node.GetExpressionSequnece().Apply(this);
                    node.GetExpression().Apply(this);
                }



                if (node.GetExpression().NodeType != formalParam.DataType)
                    _exceptionList.Add(new SemanticException(string.Format("Expected type {0} got {1}. Line:{2} Pos:{3}",
                        formalParam.DataType, node.GetExpression().NodeType, node.GetComma().Line, node.GetComma().Pos)));
                else if (formalParam.DataType.Contains("List"))
                    formalParam.DataType = "List";
            }
        }
        public override void CaseASingleExpressionSequnece(ASingleExpressionSequnece node)
        {
            VariableEntry ve;
            try
            {
                ve = (VariableEntry)SymbolTable.Find(node.Parent().NodeType, scopes.Functions.ToString());
            }
            catch (SymbolTableException e)
            {
                ve = (VariableEntry)drawFunctions.Find(x => x.Id == node.Parent().NodeType);
            }
            if (ve != null)
            {
                int lineForError = 0;
                int posForError = 0;
                if (node.Parent() is AFunctionCallScalar)
                {
                    AFunctionCallScalar af = (AFunctionCallScalar)node.Parent();
                    lineForError = af.GetOParenth().Line;
                    posForError = af.GetOParenth().Pos;
                }
                else
                {
                    AMultipleExpressionSequnece am = (AMultipleExpressionSequnece)node.Parent();
                    lineForError = am.GetComma().Line;
                    posForError = am.GetComma().Pos;
                }
                if (ve.ParamQueueCount < 1)
                {
                    _exceptionList.Add(new SemanticException(string.Format("Number of parameters doesnt match, expected {0}. Line:{1} Pos:{2}",
                        ve.ParamCount, lineForError, posForError)));
                }
                else
                {
                    VariableEntry formalParam = (VariableEntry)ve.ParamDequeue(false);
                    node.GetExpression().Apply(this);
                    if (!(formalParam.DataType == "List" && node.GetExpression().NodeType.Contains("List")))
                    {
                        if (node.GetExpression().NodeType != formalParam.DataType)
                        {
                            _exceptionList.Add(new SemanticException(string.Format("Expected type {0} got {1}. Line:{2} Pos:{3}",
                                formalParam.DataType, node.GetExpression().NodeType, lineForError, posForError)));
                        }
                    }
                }
            }
            else
                throw new SemanticException("Function in SingleSequenceExpression not found");

        }
        #endregion
        #endregion
        #endregion
        #endregion

        [Obsolete("For testing only")]
        private void TESTPrintParentTree(Node node)
        {
            object nody = NodeCast.Instance.Cast(node);
            while (nody != null)
            {
                Node n = (Node)nody;
                Console.WriteLine(n.GetType());

                nody = NodeCast.Instance.Cast(n.Parent());
            }
        }

    }

    class IdCollector : DepthFirstAdapter
    {
        //Once finished remove symbol collection from templ and func notes in semanticanalyser

        //Gather Template and Function ids
        public SymbolTable sa = SymbolTable.GetInstance();
        private VariableEntry ve = new VariableEntry();

        List<VariableEntry> reservedFunctionNames;
        public List<Exception> ExceptionList;

        public IdCollector(List<VariableEntry> listIn, ref List<Exception> exceptionList)
        {
            reservedFunctionNames = listIn;
            this.ExceptionList = exceptionList;
        }

        public override void CaseAFunc(AFunc node)
        {
            ve = new VariableEntry() { Id = node.GetId().Text, Scope = scopes.Functions.ToString(), ScopeLevel = 0, DataType = "function" };

            node.GetParamsRecursive().Apply(this);

            if (node.GetFuncReturn() is ATypeFuncReturn)
            {
                node.GetFuncReturn().Apply(this);  //adds return type
            }
            else
            {
                ve.DataType = "void";
            }
            sa.Add(ve);
        }

        public override void CaseATypeFuncReturn(ATypeFuncReturn node)
        {
            node.GetType().Apply(this);
            if (node.GetType().BaseNode == "id")
            {
                try
                {
                    VariableEntry vt = (VariableEntry)sa.Find(node.GetType().ToString(), scopes.Functions.ToString());
                    if (vt.DataType == "templates")
                        ve.DataType = node.GetType().ToString().ToLower().Trim();
                    else
                        ExceptionList.Add(new SemanticException(string.Format("Return type needs to be a basic type or a template type. Line:{0} pos:{1}",
                            node.GetTReturn().Line, node.GetTReturn().Pos)));
                }
                catch (SymbolTableException e)
                {
                    ExceptionList.Add(new SemanticException(string.Format("A valid template with name {2} doesn't exist. Line:{0} pos:{1}",
                            node.GetTReturn().Line, node.GetTReturn().Pos, node.GetType().ToString())));
                }
            }
            else if (node.GetType().ToString() == "entity")
                ExceptionList.Add(new SemanticException(string.Format("Return type can't be entity needs to be a template type. Line:{0} pos:{1}",
                            node.GetTReturn().Line, node.GetTReturn().Pos)));
            else
                ve.DataType = node.GetType().ToString().ToLower().Trim();
        }
        public override void CaseAIdType(AIdType node)
        {
            node.BaseNode = "id";
        }

        public override void CaseAParam(AParam node)
        {
            VariableEntry paramVe = new VariableEntry() { Id = node.GetId().Text, DataType = node.GetType().ToString().Trim(), Scope = ve.Id, ScopeLevel = 0 };
            if (!ve.VarParamIdExists(paramVe))
            {
                sa.Add(paramVe);
                ve.ParamEnqueue(paramVe);
            }
            else
                throw new SemanticException("param already exists");
        }

        public override void CaseATempl(ATempl node)
        {
            sa.Add(new VariableEntry() { Id = node.GetId().Text, Scope = scopes.Functions.ToString(), ScopeLevel = 0, DataType = "templates" });
        }
    }
}
